﻿using Microsoft.Win32;
using OpenHardwareMonitor.Hardware;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;

namespace WindowsStateService.Monitor
{
    public class UpdateVisitor : IVisitor
    {
        public void VisitComputer(IComputer computer)
        {
            computer.Traverse(this);
        }
        public void VisitHardware(IHardware hardware)
        {
            hardware.Update();
            foreach (IHardware subHardware in hardware.SubHardware)
                subHardware.Accept(this);
        }
        public void VisitSensor(ISensor sensor) { }
        public void VisitParameter(IParameter parameter) { }
    }

    public class ComputerInfo
    {

        /// <summary>
        /// 系统版本
        /// <para>示例：Windows 10 Enterprise</para>
        /// </summary>
        public static string OSProductName { get; } = (string)Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", "ProductName", 0);

        /// <summary>
        /// 操作系统版本
        /// <para>示例：Microsoft Windows 10.0.18363</para>
        /// </summary>
        public static string OSDescription { get; } //= System.Runtime.InteropServices.RuntimeInformation.OSDescription;

        /// <summary>
        /// 操作系统架构（<see cref="Architecture">）
        /// <para>示例：X64</para>
        /// </summary>
        public static string OSArchitecture { get; }// = System.Runtime.InteropServices.RuntimeInformation.OSArchitecture.ToString();

        /// <summary>
        /// 获取系统信息
        /// </summary>
        /// <returns></returns>
        public static SystemInfo GetSystemInfo()
        {
            SystemInfo systemInfo = new SystemInfo();

            var osProductName = OSProductName.Trim().Replace(" ", "_");
            var osVersionNames = Enum.GetNames(typeof(OSVersion)).ToList();

            for (int i = 0; i < osVersionNames.Count; i++)
            {
                var osVersionName = osVersionNames[i];
                if (osProductName.Contains(osVersionName))
                {
                    systemInfo.OSVersion = (OSVersion)Enum.Parse(typeof(OSVersion), osVersionName);
                    systemInfo.WindowsVersion = osProductName.Replace(osVersionName, "").Replace("_", " ");
                }
            }

            ManagementClass mc = new ManagementClass("Win32_OperatingSystem");
            ManagementObjectCollection moc = mc.GetInstances();

            systemInfo.WindowsVersionNo = OSDescription;
            systemInfo.Architecture = OSArchitecture;

            return systemInfo;
        }

        public static CPUInfo GetCPUInfo()
        {
            var cpuInfo = new CPUInfo();
            var cpuInfoType = cpuInfo.GetType();
            var cpuInfoFields = cpuInfoType.GetProperties().ToList();
            var moc = new ManagementClass("Win32_Processor").GetInstances();
            foreach (var mo in moc)
            {
                foreach (var item in mo.Properties)
                {
                    if (cpuInfoFields.Exists(f => f.Name == item.Name))
                    {
                        var p = cpuInfoType.GetProperty(item.Name);
                        p.SetValue(cpuInfo, item.Value, null);
                    }
                }
            }

            UpdateVisitor updateVisitor = new UpdateVisitor();
            Computer myComputer = new Computer();
            myComputer.Open();
            //启动主板监测
            myComputer.MainboardEnabled = false;
            //启动CPU监测
            myComputer.CPUEnabled = true;
            //启动内存监测
            myComputer.RAMEnabled = false;
            //启动GPU监测
            myComputer.GPUEnabled = false;
            //启动风扇监测
            myComputer.FanControllerEnabled = false;
            //启动硬盘监测
            myComputer.HDDEnabled = false;

            myComputer.Accept(updateVisitor);

            //IList<float?> sensors_loads = new List<float?>();
            IList<float?> sensors_temperatures = new List<float?>();
            foreach (var hardware in myComputer.Hardware)
            {
                if (hardware.HardwareType == HardwareType.CPU)
                {
                    foreach(var sensor in hardware.Sensors)
                    {
                        //if(sensor.SensorType== SensorType.Load)
                        //{
                        //    sensors_loads.Add(sensor.Value);
                        //}
                        if (sensor.SensorType == SensorType.Temperature)
                        {
                            sensors_temperatures.Add(sensor.Value);
                        }
                    }
                }
            }
            cpuInfo.Usage = (float)GetCPULoad();
            cpuInfo.Temperature = sensors_temperatures.Average();
            return cpuInfo;
        }

        public static double GetCPULoad()
        {
            double sum = 0;
            double count = 1;
            try
            {
                ManagementObjectSearcher searcher = new ManagementObjectSearcher("select * from Win32_Processor");
                
                foreach (ManagementObject obj in searcher.Get())
                {
                    // 获取LoadPercentage属性，这是CPU当前负载的百分比
                    if (obj == null || obj["LoadPercentage"] == null)
                        return 0;
                    UInt16 value = (UInt16)obj["LoadPercentage"];
                    sum += value;
                    count++;
                }
            }catch
            {
                return 0;
            }
            return Math.Round(sum / count, 0);
        }

        /// <summary>
        /// 内存信息
        /// </summary>
        /// <returns></returns>
        public static RAMInfo GetRAMInfo()
        {
            var ramInfo = new RAMInfo();

            var totalPhysicalMemory = TotalPhysicalMemory;
            var memoryAvailable = MemoryAvailable;

            var conversionValue = 1024.0 * 1024.0 * 1024.0;

            ramInfo.TotalPhysicalMemoryGBytes = Math.Round((double)(totalPhysicalMemory / conversionValue), 1);
            ramInfo.MemoryAvailableGBytes = Math.Round((double)(memoryAvailable / conversionValue), 1);
            ramInfo.UsedMemoryGBytes = Math.Round((double)((totalPhysicalMemory - memoryAvailable) / conversionValue), 1);
            ramInfo.UsedMemoryRatio = (int)(((totalPhysicalMemory - memoryAvailable) * 100.0) / totalPhysicalMemory);

            return ramInfo;
        }

        /// <summary>
        /// 总物理内存（B）
        /// </summary>
        /// <returns></returns>
        public static long TotalPhysicalMemory
        {
            get
            {
                long totalPhysicalMemory = 0;

                ManagementClass mc = new ManagementClass("Win32_ComputerSystem");
                ManagementObjectCollection moc = mc.GetInstances();
                foreach (ManagementObject mo in moc)
                {
                    if (mo["TotalPhysicalMemory"] != null)
                    {
                        totalPhysicalMemory = long.Parse(mo["TotalPhysicalMemory"].ToString());
                    }
                }
                return totalPhysicalMemory;
            }
        }

        /// <summary>
        /// 获取可用内存（B）
        /// </summary>
        public static long MemoryAvailable
        {
            get
            {
                long availablebytes = 0;
                ManagementClass mos = new ManagementClass("Win32_OperatingSystem");
                foreach (ManagementObject mo in mos.GetInstances())
                {
                    if (mo["FreePhysicalMemory"] != null)
                    {
                        availablebytes = 1024 * long.Parse(mo["FreePhysicalMemory"].ToString());
                    }
                }
                return availablebytes;
            }
        }

        /// <summary>
        /// 屏幕信息
        /// </summary>
        public static GPUInfo GetGPUInfo()
        {
            GPUInfo gPUInfo = new GPUInfo();
            gPUInfo.CurrentResolution = MonitorHelper.GetResolution();
            gPUInfo.MaxScreenResolution = GetGPUInfo2();

            UpdateVisitor updateVisitor = new UpdateVisitor();
            Computer myComputer = new Computer();
            myComputer.Open();
            //启动主板监测
            myComputer.MainboardEnabled = true;
            //启动CPU监测
            myComputer.CPUEnabled = true;
            //启动内存监测
            myComputer.RAMEnabled = true;
            //启动GPU监测
            myComputer.GPUEnabled = true;
            //启动风扇监测
            myComputer.FanControllerEnabled = true;
            //启动硬盘监测
            myComputer.HDDEnabled = true;

            myComputer.Accept(updateVisitor);

            foreach (var hardware in myComputer.Hardware)
            {
                if (hardware.HardwareType == HardwareType.GpuAti || hardware.HardwareType == HardwareType.GpuNvidia)
                {
                    // 遍历 CPU 的所有传感器
                    foreach (var sensor in hardware.Sensors)
                    {
                        if (sensor.SensorType == SensorType.Load && sensor.Name == "GPU Total") // Load 传感器类型代表使用率
                        {
                           // gPUInfo.Usage = sensor.Value;
                        }
                        if (sensor.SensorType == SensorType.Temperature && sensor.Name == "GPU Package") // Load 传感器类型代表使用率
                        {
                           // gPUInfo.Temperature = sensor.Value;
                        }
                    }
                }
            }

            return gPUInfo;
        }

        /// <summary>
        /// 获取最大分辨率
        /// </summary>
        /// <returns></returns>
        private static Size GetMaximumScreenSizePrimary()
        {
            var scope = new System.Management.ManagementScope();
            var q = new System.Management.ObjectQuery("SELECT * FROM CIM_VideoControllerResolution");

            UInt32 maxHResolution = 0;
            UInt32 maxVResolution = 0;

            using (var searcher = new System.Management.ManagementObjectSearcher(scope, q))
            {
                var results = searcher.Get();

                foreach (var item in results)
                {
                    if ((UInt32)item["HorizontalResolution"] > maxHResolution)
                        maxHResolution = (UInt32)item["HorizontalResolution"];

                    if ((UInt32)item["VerticalResolution"] > maxVResolution)
                        maxVResolution = (UInt32)item["VerticalResolution"];
                }
            }
            return new Size((int)maxHResolution, (int)maxVResolution);
        }

        /// <summary>
        /// 获取最大分辨率2
        /// CurrentHorizontalResolution:1920
        /// CurrentVerticalResolution:1080
        /// </summary>
        /// <returns></returns>
        public static Size GetGPUInfo2()
        {
            var gpu = new StringBuilder();
            var moc = new ManagementObjectSearcher("select * from Win32_VideoController").Get();

            var currentHorizontalResolution = 0;
            var currentVerticalResolution = 0;

            foreach (var mo in moc)
            {
                foreach (var item in mo.Properties)
                {
                    if (item.Name == "CurrentHorizontalResolution" && item.Value != null)
                        currentHorizontalResolution = int.Parse((item.Value.ToString()));
                    if (item.Name == "CurrentVerticalResolution" && item.Value != null)
                        currentVerticalResolution = int.Parse((item.Value.ToString()));
                    //gpu.Append($"{item.Name}:{item.Value}\r\n");
                }
            }
            //var res = gpu.ToString();
            //return res;
            return new Size(currentHorizontalResolution, currentVerticalResolution);
        }

        /// <summary>
        /// 磁盘信息
        /// </summary>
        public static DiskInfo GetDiskInfo()
        {
            List<DiskPartitionInfo> diskInfos = new List<DiskPartitionInfo>();
            DiskInfo disk = new DiskInfo();
            disk.DiskInfos = diskInfos;
            try
            {
                var moc = new ManagementClass("Win32_LogicalDisk").GetInstances();
                foreach (ManagementObject mo in moc)
                {
                    var diskInfo = new DiskPartitionInfo();
                    var diskInfoType = diskInfo.GetType();
                    var diskInfoFields = diskInfoType.GetProperties().ToList();

                    foreach (var item in mo.Properties)
                    {
                        if (diskInfoFields.Exists(f => f.Name == item.Name))
                        {
                            var p = diskInfoType.GetProperty(item.Name);
                            p.SetValue(diskInfo, item.Value, null);
                        }
                    }
                    diskInfos.Add(diskInfo);
                    
                }
                foreach(var diskInfo in diskInfos)
                {
                    diskInfo.Usage = 1 - diskInfo.FreeSpace / diskInfo.Size;
                }
                

                //B转GB
                for (int i = 0; i < diskInfos.Count; i++)
                {
                    diskInfos[i].Size = Math.Round((double)(diskInfos[i].Size / 1024.0 / 1024.0 / 1024.0), 1);
                    diskInfos[i].FreeSpace = Math.Round((double)(diskInfos[i].FreeSpace / 1024.0 / 1024.0 / 1024.0), 1);
                }
                
                UpdateVisitor updateVisitor = new UpdateVisitor();
                Computer myComputer = new Computer();
                myComputer.Open();
                //启动主板监测
                myComputer.MainboardEnabled = false;
                //启动CPU监测
                myComputer.CPUEnabled = false;
                //启动内存监测
                myComputer.RAMEnabled = false;
                //启动GPU监测
                myComputer.GPUEnabled = false;
                //启动风扇监测
                myComputer.FanControllerEnabled = false;
                //启动硬盘监测
                myComputer.HDDEnabled = true;

                myComputer.Accept(updateVisitor);
                
                foreach (var hardware in myComputer.Hardware)
                {
                    if (hardware.HardwareType == HardwareType.HDD)
                    {
                        // 遍历 CPU 的所有传感器
                        foreach (var sensor in hardware.Sensors)
                        {
                            if (sensor.SensorType == SensorType.Load) // Load 传感器类型代表使用率
                            {
                                disk.Usage = sensor.Value;
                            }
                            if (sensor.SensorType == SensorType.Temperature) // Load 传感器类型代表使用率
                            {
                                disk.Temperature = sensor.Value;
                            }
                        }
                    }
                }


            }
            catch (Exception ex)
            {
                ServiceLogManager.Instance.Error(ex.StackTrace);
            }

            return disk;
        }

        public static MainBoardInfo GetMainBoardInfo()
        {
            MainBoardInfo info = new MainBoardInfo();
            UpdateVisitor updateVisitor = new UpdateVisitor();
            Computer myComputer = new Computer();
            myComputer.Open();
            //启动主板监测
            myComputer.MainboardEnabled = true;
            //启动CPU监测
            myComputer.CPUEnabled = false;
            //启动内存监测
            myComputer.RAMEnabled = false;
            //启动GPU监测
            myComputer.GPUEnabled = false;
            //启动风扇监测
            myComputer.FanControllerEnabled = true;
            //启动硬盘监测
            myComputer.HDDEnabled = false;

            myComputer.Accept(updateVisitor);

            foreach (var hardware in myComputer.Hardware)
            {
                if (hardware.HardwareType == HardwareType.Mainboard)
                {
                    info.Name = hardware.Name;
                    // 遍历 CPU 的所有传感器
                    foreach (var subhardware in hardware.SubHardware)
                    {
                        if (subhardware.HardwareType == HardwareType.SuperIO)
                        {
                            foreach (var sensor in subhardware.Sensors)
                            {
                                if (sensor.SensorType == SensorType.Temperature)
                                {
                                    info.Temperature = sensor.Value;
                                }
                                if (sensor.SensorType == SensorType.Fan)
                                {
                                    info.FanSpeed = sensor.Value;
                                }
                            }
                        }
                    }
                }
            }
            return info;
        }
    }
}
